package com.katesoft.scale4j.persistent.client;

import com.katesoft.scale4j.persistent.model.unified.AbstractPersistentEntity;
import net.jcip.annotations.ThreadSafe;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.orm.hibernate3.HibernateOperations;
import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException;

import java.util.List;

/**
 * This is extended(local) interface for well-known {@link HibernateOperations} interface.
 * <p/>
 * Few specific methods defined on top of IBO domain class, also some useful methods, that are not present in standard HibernateOperations interface added.
 *
 * @see LocalHibernateTemplate
 * @see IHibernateOperations
 * @author kate2007
 */
@ThreadSafe
public interface IHibernateOperations extends HibernateOperations
{
    /**
     * looking for entity for update by unique identifier and comparing with expectedVersion - if actual version matches with expected, then return entity.
     *
     * @param entityClass      persistent class
     * @param uniqueIdentifier primary key
     * @param expectedVersion  version that client is working with
     * @param <T>              domain entity type
     * @return domain entity, never return <code>null</code>.
     * @throws HibernateOptimisticLockingFailureException
     *                                        if actual version does not match with expectedVersion.
     * @throws EmptyResultDataAccessException if domain entity with given identifier does not exists.
     * @throws DataAccessException            in case of SQL exception
     */
    <T extends AbstractPersistentEntity> T findEntityForUpdate(Class<T> entityClass,
                                                               long uniqueIdentifier,
                                                               long expectedVersion) throws DataAccessException;

    /**
     * Return all persistent instances of the given entity class calling AbstractPersistentEntity.forceAttributesLoad method if necessary.
     * <p/>
     * Note: Use queries or criteria for retrieving a specific subset.
     *
     * @param entityClass    a persistent class
     * @param forceDirtyLoad to force load? this means that forceAttributesLoad method will be invoked if necessary.
     * @return a {@link List} containing 0 or more persistent instances
     * @throws org.springframework.dao.DataAccessException
     *          if hibernate error or SQL exception occurs.
     * @see com.katesoft.scale4j.persistent.model.base.IDirtyLoadableEntity#forceAttributesLoad()
     */
    <T extends AbstractPersistentEntity> List<T> loadAll(Class<T> entityClass,
                                                         boolean forceDirtyLoad) throws DataAccessException;

    /**
     * delete all entities of the specific class.
     *
     * @param clazz entity to delete.
     * @throws org.springframework.dao.DataAccessException
     *          if hibernate error or SQL exception occurs.
     */
    void deleteAll(final Class<?> clazz) throws DataAccessException;

    /**
     * perform entity load by provided global unique identifier.
     *
     * @param persistentClazz domain class.
     * @param guid            global unique identifier of entity.
     * @param forceDirtyLoad  to force load? this means that forceAttributesLoad method will be invoked if necessary.
     * @param <T>             type of entity.
     * @return loaded entity or <code>null</code>.
     * @throws org.springframework.dao.DataAccessException
     *          if hibernate error or SQL exception occurs.
     * @see com.katesoft.scale4j.persistent.model.unified.IBO#getGlobalUniqueIdentifier()
     */
    <T extends AbstractPersistentEntity> T loadByGlobalUniqueIdentifier(Class<T> persistentClazz,
                                                                        String guid,
                                                                        boolean forceDirtyLoad) throws DataAccessException;

    /**
     * perform entity load by provided global unique identifier across all tables.
     * <p/>
     * ideally query should not cause performance issue as global unique columns indexed.
     * <p/>
     * should be used for testing purpose in most cases.
     *
     * @param guid           global unique identifier of entity.
     * @param forceDirtyLoad to force load? this means that forceAttributesLoad method will be invoked if necessary.
     * @param <T>            type of entity.
     * @return loaded entity or <code>null</code>.
     * @throws org.springframework.dao.DataAccessException
     *          if hibernate error or SQL exception occurs.
     * @see com.katesoft.scale4j.persistent.model.unified.IBO#getUniqueIdentifier()
     */
    <T extends AbstractPersistentEntity> T loadByGlobalUniqueIdentifier(String guid,
                                                                        boolean forceDirtyLoad) throws DataAccessException;
}
